home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume6 / smkdir3 < prev    next >
Encoding:
Text File  |  1989-02-03  |  14.6 KB  |  532 lines

  1. Path: xanth!nic.MR.NET!csd4.milw.wisc.edu!leah!itsgw!steinmetz!uunet!allbery
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Newsgroups: comp.sources.misc
  4. Subject: v06i028: New version of secure mkdir
  5. Message-ID: <47761@uunet.UU.NET>
  6. Date: 29 Jan 89 21:23:48 GMT
  7. Sender: allbery@uunet.UU.NET
  8. Reply-To: doug@hal.CWRU.Edu@i.UUCP (Doug Davis at letni.UUCP)
  9. Lines: 520
  10. Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  11.  
  12. Posting-number: Volume 6, Issue 28
  13. Submitted-by: doug@hal.CWRU.Edu@i.UUCP (Doug Davis at letni.UUCP)
  14. Archive-name: smkdir3
  15.  
  16. [Still?!  ++bsa]
  17.  
  18. here is the lastest, and hopefully the last version of my secure mkdir
  19. program, if its possable replace all copys of the previous one with
  20. this one. Of course as soon as all the bugs get are found *AND* reported
  21. there might be another one. ;-)
  22.  
  23. doug
  24.  
  25.  
  26. #! /bin/sh
  27. # This is a shell archive.  Remove anything before this line, then unpack
  28. # it by saving it into a file and typing "sh file".  To overwrite existing
  29. # files, type "sh file -c".  You can also feed this as standard input via
  30. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  31. # will see the following message at the end:
  32. #        "End of shell archive."
  33. # Contents:  Makefile mkdir.c
  34. # Wrapped by doug@letni.UUCP on Thu Jan 26 20:05:38 1989
  35. # This shar file will self destruct in 4 seconds, good luck %s.
  36. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  37. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  38.   echo shar: Will not clobber existing file \"'Makefile'\"
  39. else
  40. echo shar: Extracting \"'Makefile'\" \(536 characters\)
  41. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  42. X# What kind of strrchr do we have?
  43. X# 'strrchr' for most newer unix's,  'rindex' for earlier editions
  44. X# STTRCHR    = -DSTRRCHR=rindex
  45. STRRCHR    = -DSTRRCHR=strrchr
  46. X
  47. X# Do you have a rand() function call? 
  48. X# If you don't have one, comment out the line below
  49. RAND     = -DRAND
  50. X
  51. X# for debugging,  Does not unlink the secure tree.
  52. X# DEBUG    = -DDEBUG
  53. X
  54. DEFINES    = $(STRRCHR) $(DEBUG) $(RAND)
  55. SHELL    = /bin/sh
  56. CC    = /bin/cc
  57. CFLAGS    = $(DEFINES) -O
  58. LDFLAGS    = -n
  59. X
  60. mkdir: mkdir.o
  61. X    $(CC) mkdir.o $(LDFLAGS) -o mkdir
  62. X
  63. mkdir.o: mkdir.c
  64. X    $(CC) $(CFLAGS) -c mkdir.c
  65. END_OF_FILE
  66. if test 536 -ne `wc -c <'Makefile'`; then
  67.     echo shar: \"'Makefile'\" unpacked with wrong size!
  68. fi
  69. # end of 'Makefile'
  70. fi
  71. if test -f 'mkdir.c' -a "${1}" != "-c" ; then 
  72.   echo shar: Will not clobber existing file \"'mkdir.c'\"
  73. else
  74. echo shar: Extracting \"'mkdir.c'\" \(11864 characters\)
  75. sed "s/^X//" >'mkdir.c' <<'END_OF_FILE'
  76. char version[]="mkdir (1.007)";
  77. X
  78. X/*
  79. X * Secure mkdir program, solves that nasty race problem...
  80. X *
  81. X *    13 December 1988    Doug Davis         doug@letni.lawnet.com
  82. X *                      and John Elliott IV    iv@trsvax.tandy.com
  83. X *
  84. X * Modification History: 
  85. X *  M007   9 Jan 89 Gordon Burditt       gordon@trsvax.tandy.com
  86. X *                  - Fixed the signal handler to properly handle
  87. X *                    previously ignored signals.
  88. X *                  - Fixed canIwrite() to follow SVID conventions.
  89. X *  M006   6 Jan 89 Doug Davis           doug@letni.lawnet.com
  90. X *                  - Fixed M005 so it would not leave the secure
  91. X *                    tree lying around after recipt of multple 
  92. X *                    signals.
  93. X *  M005   5 Jan 89 John Haugh II        jfh@rpp386.dallas.tx.us
  94. X *                  - Added code to abort without createing all of the
  95. X *                    directoies that were specified.
  96. X *  M004  22 Dec 88 Doug Davis           doug@letni.lawnet.com
  97. X *                  - Fixed the error handler for the second makedir() call
  98. X *                    so it will unlink the securedir if it fails.
  99. X *                  - Fixed the error handler for chown() so that
  100. X *                    it removes the working "secure" directories.
  101. X *                    if it ever fails
  102. X *                  - cleaned up some odd tabs in the comments, and ran
  103. X *                    them thru a spell checker.
  104. X *  M003  22 Dec 88 John Elliott IV      iv@trsvax.tandy.com
  105. X *                  - Fixed the spelling of my name
  106. X *                  - General readability cleanup
  107. X *                  - Fixed backwards #ifdef RAND for srand() call
  108. X *                  - Saved some storage by declaring error msgs char msg[]
  109. X *                  - Fixed call order in "cleanup" code so that if the
  110. X *                    unlink() of the securename fails, we will still try
  111. X *                    to remove our scratch directory
  112. X *                  - Some calls to error() had an errno of 0, which meant
  113. X *                    that mkdir would incorrectly exit 0.  Calls to error()
  114. X *                    now include an exit code, which error() now exits with.
  115. X *                  - Fixed case where link-into-place failed and left all
  116. X *                    our flotsam and jetsam around.  Now rmdir() everything
  117. X *                    before we call error().
  118. X *                  - Changed the two error message symbols which began with
  119. X *                    "Couldnt_" to begin with "Cant_" so the symbols will
  120. X *                    be significant in 7 characters, for those so unfortunate
  121. X *                    not to have flexnames.
  122. X *  M002  21 Dec 88 Doug Davis           doug@letni.lawnet.com
  123. X *                  - Cleaned up code, added function declarations
  124. X *                  - fixed bug in second stat's unlink code
  125. X *  M001  19 Dec 88 John Haugh II          jfn@rpp386
  126. X *                  - Fixes oops in original code, much more secure now.
  127. X *
  128. X *    Theory of operation:
  129. X *        This mkdir first makes a directory to play in, which is
  130. X *         owned by root and is mode 000.  It is made in the same
  131. X *        directory in which the user is requesting his directory.
  132. X *        In this "secure" directory, to which the user allegedly
  133. X *        has no access, the mknod(), chown(), and links for `.'
  134. X *        and `..' are performed.  The new directory is then linked
  135. X *        into place.  Finally, the "secure" directory is removed.
  136. X *
  137. X * This code copyright 1988 by Doug Davis (doug@letni.lawnet.com) 
  138. X *      You are free to modify, hack, fold, spindle, duplicate, pass-along
  139. X *      give-away, publish, transmit, or mutlate this code in any maner,
  140. X *      provided that you give credit where credit is due and don't pretend
  141. X *      that you wrote it.
  142. X * 
  143. X *  If you do my lawyers (and I have a lot of lawyers) will teach you a lesson
  144. X *  or two in copyright law that you will never ever forget.
  145. X *
  146. X */
  147. X
  148. X#define MAXPATHLEN    128        /* maximum reasonanble path length */
  149. X
  150. X#include <sys/types.h>
  151. X#include <signal.h>
  152. X#include <sys/stat.h>
  153. X#ifdef DEBUG
  154. X#  include <stdio.h>
  155. X#else /*DEBUG*/
  156. X#  define NULL    0
  157. X#endif /*DEBUG*/
  158. X
  159. X#define MKNODE    1
  160. X#define LINK    2
  161. X
  162. char Malloc_Failed[]    = "malloc() failed.";
  163. char Doesnt_Exist[]    = " does not exist.";
  164. char Cannot_Access[]    = "cannot access ";
  165. char Already_Exist[]    = " already exists.";
  166. char Secure_Failed[]    = "makedir secure parent failed ";
  167. char Cant_Link[]    = "Couldn't link to ";
  168. char Mkdir_Failed[]    = "makedir failed ";
  169. char Chown_Failed[]    = "chown() failed ";
  170. char Cant_Unlink[]    = "Couldn't unlink ";
  171. X
  172. extern char *STRRCHR();
  173. extern char *malloc();
  174. X
  175. extern int errno;
  176. extern int getpid();
  177. extern int stat();
  178. extern int chown();
  179. extern int unlink();
  180. extern int strlen();
  181. X
  182. extern unsigned short getuid();
  183. extern unsigned short getgid();
  184. extern long time();
  185. X
  186. X
  187. char *Progname;
  188. int signaled = 0;
  189. X
  190. X#ifdef RAND
  191. X  extern int rand();
  192. X#else /*RAND*/
  193. X  extern int getppid();
  194. X#endif /*RAND*/
  195. X
  196. X/* This function is part of the signal handler, it is used to prevent
  197. X * mkdir from creating all of the directories on the command line, 
  198. X * upon recipt of a signal mkdir will finish the directory that it is
  199. X * currently doing then exit
  200. X */
  201. int
  202. catch()
  203. X{
  204. X    signaled = 1;
  205. X    set_sigs(SIG_IGN);
  206. X}
  207. X
  208. main(argc, argv)
  209. int argc;
  210. char *argv[];
  211. X{
  212. X    Progname = argv[0];
  213. X    errno = 0;
  214. X
  215. X    if (argc < 2) {
  216. X        print("Usage:  ");
  217. X        print(Progname);
  218. X        print(" directory_name [ ... directory_name ]\n");
  219. X        exit(0);
  220. X    }
  221. X
  222. X    /* Catch those nasty signals that could cause us
  223. X     * to mess up the filesystem */
  224. X    set_sigs(catch);
  225. X
  226. X    while (--argc && ! signaled)
  227. X        md(*++argv); /* make each directory */
  228. X
  229. X    exit(0);
  230. X}
  231. X
  232. X
  233. int
  234. md(s)
  235. char *s;
  236. X{
  237. X    register char *basename,
  238. X                  *parent,
  239. X                  *fullname;
  240. X
  241. X    unsigned short myuserid,
  242. X                   mygroupid;
  243. X
  244. X    char securename[MAXPATHLEN],
  245. X         securedir[MAXPATHLEN],
  246. X         dotsecurename[MAXPATHLEN];
  247. X
  248. X    int    rval1,
  249. X        rval2;
  250. X
  251. X    long snum;
  252. X
  253. X    struct    stat sanity;
  254. X
  255. X    /* find out who I really am */
  256. X    myuserid = getuid();
  257. X    mygroupid = getgid();
  258. X
  259. X    /* set up the pseudo-RANDom number generation system */
  260. X#ifdef RAND
  261. X    srand(getpid());
  262. X#endif /*RAND*/
  263. X
  264. X    /* see if we are explicit or indirect */
  265. X    basename = STRRCHR(s, '/');
  266. X    if (basename == (char *)NULL) {
  267. X        fullname = malloc(strlen(s)+1);
  268. X        if (fullname == (char *)NULL) 
  269. X            error(Malloc_Failed, (char *)NULL, errno, 1);
  270. X        parent = malloc(2);
  271. X        if (parent == (char *)NULL)
  272. X            error(Malloc_Failed, (char *)NULL, errno, 1);
  273. X        parent[0] = '.';
  274. X        parent[1] = '\0';
  275. X        strcpy(fullname, s);
  276. X        basename = s;
  277. X    } else {
  278. X        fullname = malloc(strlen(s)+1);
  279. X        if (fullname == (char *)NULL) 
  280. X            error(Malloc_Failed, (char *)NULL, errno, 1);
  281. X        strcpy(fullname, s);
  282. X        *basename = '\0';
  283. X        basename++;
  284. X        parent = malloc(strlen(s) + 3);
  285. X        if (parent == (char *)NULL)
  286. X            error(Malloc_Failed, (char *)NULL, errno, 1);
  287. X        strcpy(parent, s);
  288. X        strcat(parent, "/.");
  289. X    }
  290. X
  291. X    /* Generate the secure names ... */
  292. X    do {
  293. X        /* round and round we go; where we stop depends on
  294. X         * the non-existance of securedir */
  295. X        snum = time((long *) 0L);    
  296. X#ifdef RAND
  297. X        sprintf(securedir, "%s/%ld", parent,
  298. X            (rand() % 2) ? snum + (long)rand() : snum - (long)rand());
  299. X        sprintf(securename, "%s/%ld", securedir,
  300. X            (rand() % 2) ? snum - (long)rand() : snum + (long)rand());
  301. X        sprintf(dotsecurename, "%s/./.", securename);
  302. X#else /*RAND*/
  303. X        sprintf(securedir, "%s/%ld", parent, snum - (long)getppid());
  304. X        sprintf(securename, "%s/%ld", securedir, snum + (long)getppid());
  305. X        sprintf(dotsecurename, "%s/./.", securename);
  306. X        snum += (long)getpid();
  307. X#endif /*RAND*/
  308. X    } while (stat(securedir, &sanity) == 0);
  309. X
  310. X#ifdef DEBUG
  311. X    /* spill the beans .. */
  312. X    printf("parent     == %s\n", parent);
  313. X    printf("basename   == %s\n", basename);
  314. X    printf("fullname   == %s\n", fullname);
  315. X    printf("securedir  == %s\n", securedir);
  316. X    printf("securename == %s\n", securename);
  317. X    printf("dotsecurename == %s\n", dotsecurename);
  318. X    fflush(stdout);
  319. X#endif /*DEBUG*/
  320. X
  321. X    /* let's see if our parent directory is around... */
  322. X    if ((stat(parent, &sanity)) != 0)
  323. X        error(parent, Doesnt_Exist, 0, 2);
  324. X
  325. X    /* find out if we can write here */
  326. X    if (canIwrite(&sanity, myuserid, mygroupid) != 0) 
  327. X        error(Cannot_Access, parent, 0, 2);
  328. X
  329. X    /* find out if we are going to stomp on something.. */
  330. X    if ((stat(fullname, &sanity)) == 0) 
  331. X        error(fullname, Already_Exist, 0, 2);
  332. X
  333. X    /* make secure parent directory (note the mode of 0) */
  334. X    if (makedir(parent, securedir, 0) > 0) 
  335. X        error(Secure_Failed, securedir, errno, 2);
  336. X    
  337. X    /* now make our directory underneath it */
  338. X    if (makedir(parent, securename, 0777) > 0) {
  339. X        rmdir(securedir);
  340. X        error(Mkdir_Failed, securedir, errno, 3);
  341. X    }
  342. X
  343. X    /* do that eerie little chown() that's the "root" of all our problems */
  344. X    if (chown(dotsecurename, myuserid, mygroupid) != 0) {
  345. X        rmdir(securename);
  346. X        rmdir(securedir);
  347. X        error(Chown_Failed, dotsecurename, errno, 3);
  348. X    }
  349. X    
  350. X    /* do a quick sanity check, just to annoy someone trying
  351. X     * to trick mkdir into chowning something it shouldn't.. */
  352. X    if ((stat(fullname, &sanity)) == 0) {
  353. X        /* What happened?  This wasn't here a couple of calls ago... */
  354. X        rmdir(securename);
  355. X        rmdir(securedir);
  356. X        error(fullname, Already_Exist, 0, 4);
  357. X    }
  358. X        
  359. X    /* okay, put it where it belongs */
  360. X    if ((link(securename, fullname)) < 0) {
  361. X        rmdir(securename);
  362. X        rmdir(securedir);
  363. X        error(Cant_Link, fullname, errno, 4);
  364. X    }
  365. X    
  366. X    /* remove all our rubbish, and tidy everything up.. */
  367. X    if (parent != (char *)NULL) 
  368. X        free(parent);
  369. X    if (fullname != (char *)NULL)
  370. X        free(fullname);
  371. X    rval1 = unlink(securename);
  372. X        /* Even if the unlink() fails, we really should at least
  373. X         * attempt to remove our scratch directory... */
  374. X    rval2 = rmdir(securedir);
  375. X    if (rval1 < 0)
  376. X        error(Cant_Unlink, securename, errno, 5);
  377. X    if (rval2 != 0)
  378. X        error(Cant_Unlink, securedir, errno, 5);
  379. X
  380. X    return (0);
  381. X}
  382. X
  383. int
  384. makedir(parent, dir, mode)
  385. char *parent, *dir;
  386. int mode;
  387. X{
  388. X    char dotdot[MAXPATHLEN];
  389. X
  390. X#ifdef DEBUG
  391. X    printf("mkdir(%s, %s)\n", parent, dir);
  392. X    fflush(stdout);
  393. X#endif /*DEBUG*/
  394. X
  395. X    /* put the node together */
  396. X    if ((mknod(dir, S_IFDIR | mode, 0)) < 0) 
  397. X        return (MKNODE);
  398. X
  399. X    /* make dot */
  400. X    strcpy(dotdot, dir);
  401. X    strcat(dotdot, "/.");
  402. X    if ((link(dir, dotdot)) < 0) 
  403. X        return (LINK);
  404. X
  405. X    /* make dotdot */
  406. X    strcat(dotdot, ".");
  407. X    if ((link(parent, dotdot)) < 0) 
  408. X        return (LINK);
  409. X
  410. X    return (0);
  411. X}
  412. X
  413. int
  414. rmdir(dir)
  415. char *dir;
  416. X{
  417. X    char dots[MAXPATHLEN];
  418. X
  419. X#ifdef DEBUG
  420. X    printf("rmdir(%s)\n", dir);
  421. X    fflush(stdout);
  422. X#endif /*DEBUG*/
  423. X
  424. X    strcpy(dots, dir);
  425. X    strcat(dots, "/.");
  426. X
  427. X    /* unlink(".") */
  428. X    if (unlink(dots) < 0)
  429. X        return (LINK);
  430. X
  431. X    /* unlink("..") */
  432. X    strcat(dots, ".");
  433. X    if (unlink(dots) < 0)
  434. X        return (LINK);
  435. X
  436. X    /* unlink the directory itself */
  437. X    if (unlink(dir) < 0)
  438. X        return (LINK);
  439. X
  440. X    return (0);
  441. X}
  442. X
  443. int
  444. print(s)
  445. char *s;
  446. X{
  447. X    return (write(2, s, strlen(s)));
  448. X}
  449. X
  450. error(s1, s2, err, ecode)
  451. char *s1,
  452. X     *s2;
  453. int err,
  454. X    ecode;
  455. X{
  456. X    print(Progname);
  457. X    print(": ");
  458. X    print(s1);
  459. X    errno = err;
  460. X    if (s2 != (char *)NULL)
  461. X        print(s2);
  462. X    if (err != 0) 
  463. X        perror(" ");
  464. X    else 
  465. X        print("\n");
  466. X    exit(ecode);
  467. X}
  468. X
  469. int
  470. set_sigs(func)
  471. int *(*func)();
  472. X{
  473. X    register int i;
  474. X
  475. X    for (i=1; i<=NSIG ; i++)
  476. X        if (signal(i, SIG_IGN) != SIG_IGN)
  477. X            signal(i, func); /* point it at the catch() routine. */
  478. X
  479. X    return (0);
  480. X}
  481. X
  482. int
  483. canIwrite(stbuff, uid, gid)
  484. register struct stat *stbuff;
  485. register unsigned short uid,
  486. X                        gid;
  487. X{
  488. X    /* we let root get away with anything... */
  489. X    if (uid == 0)
  490. X        return (0);
  491. X
  492. X    /* can I write in it as an OWNER ? */
  493. X    if (uid == stbuff->st_uid)
  494. X        if (stbuff->st_mode & 0200)
  495. X            return (0);
  496. X        else
  497. X    /* okay, so I can't write here.. */
  498. X            return (-1);
  499. X
  500. X    /* okay, so how about as a GROUP ? */
  501. X    if (gid == stbuff->st_gid)
  502. X        if (stbuff->st_mode & 0020)
  503. X            return (0);
  504. X        else
  505. X    /* okay, so I can't write here.. */
  506. X            return (-1);
  507. X
  508. X    /* alright, how about an OTHER ? */
  509. X    if (stbuff->st_mode & 0002)
  510. X        return (0);
  511. X
  512. X    /* okay, so I can't write here.. */
  513. X    return (-1);
  514. X}
  515. X
  516. X#ifdef DEBUG
  517. unlink(s)
  518. char *s;
  519. X{
  520. X    printf("Unlink(%s)\n", s);
  521. X    fflush(stdout);
  522. X}
  523. X#endif /*DEBUG*/
  524. END_OF_FILE
  525. if test 11864 -ne `wc -c <'mkdir.c'`; then
  526.     echo shar: \"'mkdir.c'\" unpacked with wrong size!
  527. fi
  528. # end of 'mkdir.c'
  529. fi
  530. echo shar: End of shell archive.
  531. exit 0
  532.